"""
自定义的logger, 和logging功能一致, 调用方法也一致
"""

import time, datetime, sys, os
import inspect
from glob import glob
from threading import Lock, Thread
from queue import Queue

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0


class Logger:
    _levelToName = {
        CRITICAL: "CRITICAL",
        ERROR: "\033[91m ERROR \033[0m",
        WARNING: "\033[93m WARNING \033[0m",
        INFO: "INFO",
        DEBUG: "DEBUG",
        NOTSET: "NOTSET",
    }
    lock = Lock()

    def __init__(self) -> None:
        self.level = INFO
        self.filemode = "a"
        self.filename = None
        self.file_handle = None
        self.format = "%(asctime)s - %(levelname)-9s - %(filename)-8s line %(lineno)s , %(message)s"  # 日志输出的格式, -8表示占位符，让输出左对齐，输出长度都为8位
        self.datefmt = "%Y-%m-%d %H:%M:%S"  # 时间输出的格式
        self.max_log_size = 10
        self.buffer_list = Queue()
        Thread(target=self.run_loop).start()

    def run_loop(self):
        while True:
            try:
                str_line = self.buffer_list.get_nowait()
                self.write_to_file(str_line)
            except:
                pass
            time.sleep(0.1)


    def error(self, message):
        level = ERROR
        callingframe = sys._getframe(1)
        callingframe_info = inspect.getframeinfo(callingframe)
        self.build_line(message, level, callingframe_info)

    def warning(self, message):
        level = WARN
        callingframe = sys._getframe(1)
        callingframe_info = inspect.getframeinfo(callingframe)
        self.build_line(message, level, callingframe_info)

    def debug(self, message):
        level = DEBUG
        callingframe = sys._getframe(1)
        callingframe_info = inspect.getframeinfo(callingframe)
        self.build_line(message, level, callingframe_info)

    def info(self, message):
        level = INFO
        callingframe = sys._getframe(1)
        callingframe_info = inspect.getframeinfo(callingframe)
        self.build_line(message, level, callingframe_info)

    def build_line(self, message, level, callingframe_info):
        if level < self.level:
            return
        key_value = {
            "asctime": datetime.datetime.now().strftime(self.datefmt),
            "filename": callingframe_info.filename,
            "levelname": self._levelToName[level],
            "lineno": callingframe_info.lineno,
            "function": callingframe_info.function,
            "message": message,
        }

        str_line = self.format % key_value
        self.buffer_list.put(str_line)

    def write_to_file(self, str_line):
        if self.filename is None:
            print(str_line)
        else:
            try:
                if self.lock.acquire():
                    file_size = os.stat(self.filename).st_size
                    if file_size > self.max_log_size* 1024 * 1024:
                        self.file_handle = open(self.filename, 'w')
                    self.file_handle.write(str_line + "\n")
                    self.file_handle.flush()
            finally:
                self.lock.release()

    def basicConfig(
        self,
        level=None,
        filename=None,
        filemode=None,
        format=None,
        datefmt=None,
        max_log_size=10,
    ):
        # 检查log文件夹下的文件大小, 删除旧日志
        self.max_log_size = max_log_size

        if level != None:
            for key, value in self._levelToName.items():
                if level == value:
                    self.level = key

        if filemode != None:
            self.filemode = filemode

        if filename != None:
            self.filename = filename
            self.file_handle = open(self.filename, filemode)
            self.remove_log()

        if format != None:
            self.format = format

        if datefmt != None:
            self.datefmt = datefmt

    def remove_log(self):
        """
        日志文件按创建时间倒序排列, max log size内的文件保留, 其余删除
        """
        log_filelist = glob(os.path.dirname(self.filename) + "/*.log")
        log_filelist.sort(key=os.path.getctime, reverse=True)  # 根据文件的创建时间排序
        file_idx = 0
        logs_size = 0
        for file_path in log_filelist:
            file_idx += 1
            logs_size += os.stat(file_path).st_size
            if logs_size > (self.max_log_size * 1024 * 1024):
                break
        for idx_ in range(file_idx, len(log_filelist)):
            os.remove(log_filelist[idx_])


logging = Logger()

if __name__ == "__main__":
    logging.basicConfig(level="INFO")
    logging.info("hello world")